/***********************************************************************************************************************
 * ############################################# Application AdewebLite #############################################
 * AdewebLite Android est une application permettant de consulter des emplois du temps fournis par l'université UHP
 * avec ou sans connexion internet (informations gardées en mémoire à chaque synchronisation). Et utilisant la web
 * API ADE pour collecter les données.
 * @author Andrianjafintrimo Victor, Zanette Sébastien
 * 
 * Basée sur l'application du même nom, utilisant le flux RSS (données à traiter), de :
 * @author Schnell Michaël, Zanette Sébastien
 * **********************************************************************************************************************
 */

package ade.database;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import ade.exception.AAAException;
import ade.exception.AAAInternalException;
import ade.exception.UnknownScheduleException;
import ade.schedule.Lesson;
import ade.schedule.Schedule;
import ade.schedule.StudentNumber;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.DatabaseUtils.InsertHelper;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import java.util.Hashtable;

/**
 * Classe contenant des fonctions faisant les liens entre les requêtes SQL et
 * les Objets java.
 *
 * @author Zanette Sébastien,
 * @author Andrianjafintrimo Victorrimo
 */
public class Database {

    private static final int VERSION_BDD = 1;
    private static final String NOM_BDD = "ADEWEBLITE.db";
    private static final String TABLE_SCHEDULE = "SCHEDULE";
    private static final String COL_NAME = "NAME";
    private static final int NUM_COL_NAME = 0;
    private static final String COL_PROJECT_ID = "PROJECTID";
    private static final int NUM_COL_PROJECT_ID = 1;
    private static final String COL_RESSOURCE_ID = "RESSOURCEID";
    private static final int NUM_COL_RESSOURCE_ID = 2;
    private static final String COL_STUDENT_NUM = "STUDENTNUM";
    private static final int NUM_COL_STUDENT_NUM = 3;
    private static final String COL_SUB_PERIOD = "PERIOD";
    private static final int NUM_COL_SUB_PERIOD = 4;
    private static final String COL_LAST_MODIF = "LASTMODIF";
    private static final int NUM_COL_LAST_MODIF = 5;
    private static final String COL_STATUS = "STATUS";
    private static final int NUM_COL_STATUS = 6;
    private static final String COL_CREATED = "CREATED";
    private static final int NUM_COL_CREATED = 7;
    
    private static final String TABLE_LESSON = "LESSON";
    private static final String COL_LESSON_ID = "LESSON_ID";
    private static final int NUM_COL_LESSON_ID = 0;
    private static final String COL_TITLE = "TITLE";
    private static final int NUM_COL_TITLE = 1;
    private static final String COL_TIME = "TIME";
    private static final int NUM_COL_TIME = 2;
    private static final String COL_SCHEDULE = "SCHEDULE";
    private static final int NUM_COL_SCHEDULE = 3;
    private static final String COL_TYPE = "TYPE";
    private static final int NUM_COL_TYPE = 4;
    public static final String COL_CHANGE = "CHANGE";
    public static final int NUM_COL_CHANGE = 5;
    private static final String COL_LASTMODIF = "LASTMODIF";
    private static final int NUM_COL_LASTMODIF = 6;
    private static final String COL_ROOM = "ROOM";    
    private static final int NUM_COL_ROOM = 7;
    private static final String COL_GROUP = "GROUPS";
    private static final int NUM_COL_GROUP = 8;
    private static final String COL_TEACHER = "TEACHER";
    private static final int NUM_COL_TEACHER = 9;
    private static final String COL_COLOR = "COLOR";
    private static final int NUM_COL_COLOR = 10;
    private static final String COL_NOTE = "NOTE";
    private static final int NUM_COL_NOTE = 11;
    
    private static final String TABLE_LESSON_HISTORY = "LESSON_HISTORY";
    
    private static final String TABLE_STUDENT_NUMBER = "STUDENT_NUMBER";
    private static final String COL_STUDENT_NUMBER = "STUDENT_NUMBER";
    private static final int NUM_COL_STUDENT_NUMBER = 0;
    private static final String COL_RESSOURCEID = "RESSOURCEID";
    private static final int NUM_COL_RESSOURCEID = 1;
    
    private static CreateDatabases instance = null;
    private SQLiteDatabase bdd;
    private CreateDatabases cd;
    private InsertHelper lessonInsert;
    private InsertHelper lessonHistoryInsert;
    /**
     * Stock les instances de
     * <code>CreateDatabase</code> pour chaque contexte.
     */
    protected static Hashtable<Context, CreateDatabases> databases = new Hashtable<Context, CreateDatabases>();

    /**
     * Constructeur de
     * <code>Database</code>. Créer une nouvelle instance de
     * <code>CreateDatabase</code>
     *
     * @param context contexte
     */
    protected Database(Context context) {
        this.cd = new CreateDatabases(context, NOM_BDD, null, VERSION_BDD);
    }

    /**
     * Constructeur de
     * <code>Database</code>. Récupère l'instance existante.
     */
    public Database() {
        this.cd = Database.instance;
    }

    /**
     * Créer une instance de la classe
     * <code>CreateDatabase</code>.
     *
     * @param context contexte
     */
    public static void createInstance(Context context) {
        Database.instance = new CreateDatabases(context, NOM_BDD, null, VERSION_BDD);
    }

    /**
     * Retourne un booléen testant l'existance d'une instance de la classe
     * <code>Database</code>.
     *
     * @return vrai si
     * <code>Database</code> à été instancié, faux sinon.
     */
    public static boolean isBuilt() {
        return (Database.instance != null);
    }

    /**
     * Ouvre la base de données en lecture et écriture.
     */
    public void open() {
        //on ouvre la BDD en écriture  
        this.bdd = this.cd.getWritableDatabase();
        this.lessonInsert = new InsertHelper(this.bdd, TABLE_LESSON);
        this.lessonHistoryInsert = new InsertHelper(this.bdd, TABLE_LESSON_HISTORY);

    }

    /**
     * Ferme la base de données en lecture et écriture.
     */
    public void close() {
        //on ferme l'accès à la BDD     
        this.lessonInsert.close();
        if(this.bdd.isOpen())
            this.bdd.close();
    }

    //----------------------------------------EDT ---------------------------------------------
    /**
     * Insère un emploi du temps dans la table SCHEDULE et ses cours associés
     * dans la table LESSON.
     *
     * @param s
     * <code>Schedule</code>
     * @return -1 si échec, la ligne du tuple inséré sinon
     */
    public long insertSchedule(Schedule s) {
        this.open();
        //Création d'un ContentValues (fonctionne comme une HashMap)
        ContentValues values = new ContentValues();
        //on lui ajoute une valeur associée à une clé (qui est le nom de la colonne dans laquelle on veut mettre la valeur)
        values.put(COL_PROJECT_ID, s.getProjectId());
        values.put(COL_NAME, s.getName());
        values.put(COL_RESSOURCE_ID, s.getRessources());
        values.put(COL_SUB_PERIOD, s.getPeriod());
        values.put(COL_LAST_MODIF, s.getLastModif());
        values.put(COL_STUDENT_NUM, s.getStudentNum());
        values.put(COL_STATUS, s.getStatus());
        values.put(COL_CREATED, s.getCreated());
        long resInsert = 0;
        try {
            resInsert = bdd.insertOrThrow(TABLE_SCHEDULE, null, values);

            for (Lesson l : s) {
                this.insertLesson(l);
            }// for
            for (StudentNumber sn : s.getStudentNumList()) {
                if (this.getRessourceWithStudentNumber(sn.getStudentNumber()) == null) {
                    this.insertStudentNumber(sn);
                } else {
                    this.updateStudentNumber(sn.getStudentNumber(), sn);
                }
            }
            this.close();
            return resInsert;
        } catch (SQLException ex) {
            Log.e("adeInsert", "" + ex.getMessage());
            ex.printStackTrace();
        }
        return resInsert;
    }

    /**
     * Met à jour un emploi du temps dans la table SCHEDULE, identifié par son
     * nom.
     *
     * @param name de l'emploi du temps
     * @param s
     * <code>Schedule</code>
     * @return -1 si échec, la ligne du tuple modifié sinon
     */
    public int updateSchedule(String name, Schedule s) {
        this.open();
        //La mise à jour d'un EDT dans la BDD fonctionne plus ou moins comme une insertion
        //il faut simple préciser quelle EDT on doit mettre à jour grâce à son nom
        String newName = s.getName();
        ContentValues values = new ContentValues();
        values.put(COL_PROJECT_ID, s.getProjectId());
        values.put(COL_NAME, newName);
        values.put(COL_RESSOURCE_ID, s.getRessources());
        values.put(COL_SUB_PERIOD, s.getPeriod());
        values.put(COL_LAST_MODIF, s.getLastModif());
        values.put(COL_STATUS, s.getStatus());
        values.put(COL_CREATED, s.getCreated());
        values.put(COL_STUDENT_NUM, s.getStudentNum());

        int resUpdate = bdd.update(TABLE_SCHEDULE, values, String.format("%s = \"%s\"", COL_NAME, name), null);
        // UPDATE LESSON SET SCHEDULE = s.getName() WHERE SCHEDULE = name only if name != s.getName() 
        if (!newName.equals(name)) {
            values = new ContentValues();
            values.put(COL_SCHEDULE, s.getName());
            bdd.update(TABLE_LESSON, values, String.format("%s = \"%s\"", COL_SCHEDULE, name), null);
        }// if
        for (StudentNumber sn : s.getStudentNumList()) {
            this.updateStudentNumber(sn.getStudentNumber(), sn);
        }
        this.close();
        return resUpdate;
    }

    /**
     * Supprime un emploi du temps dans la table SCHEDULE et ses ressources
     * associées dans la table LESSON, identifié par son nom. Fait appel à la
     * fonction {@link #removeScheduleLessonsWithName(String name) removeScheduleLessonsWithName(String name)}.
     *
     * @param name nom de l'emploi du temps
     * @return 0 si aucune suppression, le nombre de tuples supprimés sinon
     */
    public int removeScheduleWithName(String name) {
        //Suppression d'un EDT de la BDD
        //On ouvre la base de donnée
        this.open();
        this.removeScheduleLessonsWithName(name);
        int errSuppr = bdd.delete(TABLE_SCHEDULE, String.format("%s = \"%s\"", COL_NAME, name), null);
        this.close();
        return errSuppr;
    }

    /**
     * Supprime tous les cours associées à un emploi du temps, identifié par son
     * nom.
     *
     * @param name nom de l'emploi du temps
     * @return -1 si échec 0 sinon
     */
    public int removeScheduleLessonsWithName(String name) {
        //Suppression d'un EDT de la BDD
        return bdd.delete(TABLE_LESSON, String.format("%s = \"%s\"", COL_SCHEDULE, name), null);
    }

    /**
     * Retourne
     * <code>Schedule</code> extrait de la table SCHEDULE grâce au nom de
     * l'emploi du temps.
     *
     * @param name nom de l'emploi du temps
     * @return
     * <code>Schedule</code>
     * @throws AAAException
     */
    public Schedule getScheduleWithName(String name) throws AAAException {
        //On ouvre a base de donnée en lecture
        this.open();
        //Récupère dans un Cursor les valeurs correspondantent à un edt contenu dans la BDD
         Cursor c = null;
        if(this.bdd.isOpen())
            c = bdd.query(TABLE_SCHEDULE, new String[]{COL_NAME, COL_PROJECT_ID, COL_RESSOURCE_ID, COL_STUDENT_NUM, COL_SUB_PERIOD, COL_LAST_MODIF, COL_STATUS, COL_CREATED}, COL_NAME + " LIKE \"" + name + "\"", null, null, null, null, null);
        Schedule s = this.cursorToSchedule(c);
        c.close();
        //ferme la base de données en lecture
       
        this.close();
        //this.bdd.close();
        if (s == null) {
            throw new UnknownScheduleException(name);
        }// if
        return s;
    }

    /**
     * Conversion d'un type
     * <code>Cursor</code> en
     * <code>Schedule</code>. Toute fonction jdbc retourne un type
     * <code>Cursor</code>, cette méthode est appelé après chaque requête afin
     * retourner directement un
     * <code>Schedule</code>.
     *
     * @param c Cursor
     * @return
     * <code>Schedule</code>, null si le curseur est vide.
     */
    private Schedule cursorToSchedule(Cursor c) {
        Schedule s = null;
        if ( c!= null && c.moveToNext()) {
            //On créé un emploi du temps
            s = new Schedule();
            //on lui affecte toutes les infos grâce aux infos contenues dans le Cursor
            s.setName(c.getString(NUM_COL_NAME));
            s.setProjectId(c.getInt(NUM_COL_PROJECT_ID));
            s.setRessources(c.getString(NUM_COL_RESSOURCE_ID));
            s.setPeriod(c.getInt(NUM_COL_SUB_PERIOD));
            s.setLastModif(c.getString(NUM_COL_LAST_MODIF));
            s.setStatus(c.getInt(NUM_COL_STATUS));
            s.setCreated(c.getString(NUM_COL_CREATED));
            s.setStudentNum(c.getString(NUM_COL_STUDENT_NUM));
        }
        //On retourne l'EDT
        return s;
    }

    /**
     * Retourne un tableau de
     * <code>String</code> contenant les noms de tous les emplois du temps
     * contenu dans la tables. Necessaire à l'affichage de la liste des emplois
     * du temps sur la page d'acceuil de l'application.
     *
     * @return tableau de
     * <code>String</code> contenant les noms de tous les emplois du temps
     */
    public String[] getSchedulesName() {
        //On ouvre a base de donnée en lecture
        this.open();
        Cursor c = bdd.query(Database.TABLE_SCHEDULE, new String[]{Database.COL_NAME},
                null, null, null, null, null);
        ArrayList<String> liste = new ArrayList<String>();
        while (c.moveToNext()) {
            liste.add(c.getString(0));
        }// while
        c.close();
        //this.bdd.close();
        this.close();
        return liste.toArray(new String[liste.size()]);
    }

    /**
     * Met à jour la date de modification (=date de dernière mise à jour) d'un
     * emploi du temps, identifié par son nom.
     *
     * @param scheduleName nom de l'emploi du temps
     * @return -1 si échec, la ligne du tuple modifié sinon
     */
    public long setLastModifSchedule(String scheduleName) {
        this.open();
        ContentValues values = new ContentValues();
        values.put(COL_LAST_MODIF, new SimpleDateFormat("yyyy/MM/dd HH:mm").format(new Date()));
        long resUpt = this.bdd.update(TABLE_SCHEDULE, values,
                String.format("%s = '%s'", COL_NAME, scheduleName),
                null);
        this.close();
        return resUpt;
    }

    /**
     * Met à jour le statut (=echec de la maj d'un emploi du temps ou non) d'un
     * emploi du temps, identifié par son nom.
     *
     * @param scheduleName nom de l'emploi du temps
     * @param status statut de l'emploi du temps
     * @return -1 si échec, la ligne du tuple modifié sinon
     */
    public long setStatus(String scheduleName, int status) {
        this.open();
        ContentValues values = new ContentValues();
        values.put(COL_STATUS, status);
        long resUpt = this.bdd.update(TABLE_SCHEDULE, values,
                String.format("%s = '%s'", COL_NAME, scheduleName),
                null);
        this.close();
        return resUpt;
    }

    //------------------------------------------------------------------------------------------------
    //----------------------------------------- Cours --------------------------------------------
    /**
     * Insère un cours dans la table LESSON.
     *
     * @param l
     * <code>Lesson</code> un cours.
     * @return -1 si échec, la ligne du tuple inséré sinon
     */
    public long insertLesson(Lesson l) {
        // Get the InsertHelper ready to insert a single row
        this.lessonInsert.prepareForInsert();

        // Add the data for each column
        this.lessonInsert.bind(1 + Database.NUM_COL_LESSON_ID, l.getLessonId());
        this.lessonInsert.bind(1 + Database.NUM_COL_TITLE, l.getTitle());
        this.lessonInsert.bind(1 + Database.NUM_COL_TIME, l.getTime());
        this.lessonInsert.bind(1 + Database.NUM_COL_SCHEDULE, l.getSchedule());
        this.lessonInsert.bind(1 + Database.NUM_COL_TYPE, l.getType());
        this.lessonInsert.bind(1 + Database.NUM_COL_CHANGE, l.getChange());
        this.lessonInsert.bind(1 + Database.NUM_COL_ROOM, l.getRoom());
        this.lessonInsert.bind(1 + Database.NUM_COL_GROUP, l.getGroups());
        this.lessonInsert.bind(1 + Database.NUM_COL_TEACHER, l.getTeacher());
        this.lessonInsert.bind(1 + Database.NUM_COL_LASTMODIF, l.getCreated());
        this.lessonInsert.bind(1 + Database.NUM_COL_COLOR, l.getColor());
        this.lessonInsert.bind(1 + Database.NUM_COL_NOTE, l.getNote());

        // Insert the row into the database.
        return this.lessonInsert.execute();
    }// insertLesson(Lesson)

    /**
     * Met à jour un cours dans la table LESSON, identifié par l'id du cours et
     * le nom de l'emploi du temps associé.
     *
     * @param oldId id du cours
     * @param oldSchedule nom de l'emploi du temps
     * @param newLesson
     * <code>Lesson</code> avec en champ les nouveaux paramètres
     * @return -1 si échec, la ligne du tuple modifié sinon
     */
    public int updateLesson(long oldId, String oldSchedule, Lesson newLesson) {
        this.open();
        //La mise à jour d'un cours dans la BDD fonctionne plus ou moins comme une insertion
        //il faut simple préciser quel cours on doit mettre à jour grâce à son ID
        ContentValues values = new ContentValues();
        values.put(COL_LESSON_ID, newLesson.getLessonId());
        values.put(COL_TITLE, newLesson.getTitle());
        values.put(COL_TIME, newLesson.getTime());
        values.put(COL_SCHEDULE, newLesson.getSchedule());
        values.put(COL_TYPE, newLesson.getType());
        values.put(COL_CHANGE, newLesson.getChange());
        values.put(COL_ROOM, newLesson.getRoom());
        values.put(COL_GROUP, newLesson.getGroups());
        values.put(COL_TEACHER, newLesson.getTeacher());
        values.put(COL_LASTMODIF, newLesson.getCreated());
        values.put(COL_COLOR, newLesson.getColor());
        values.put(COL_NOTE, newLesson.getNote());
        int resUpt = this.bdd.update(TABLE_LESSON, values,
                String.format("%s = '%s' AND %s = '%s'", COL_LESSON_ID, oldId, COL_SCHEDULE, oldSchedule),
                null);
        this.close();
        return resUpt;
    }

    /**
     * Met à jour le statut d'un cours, identifiée par l'id du cours
     *
     * @param id id du cours à mettre à jour
     * @param scheduleName nom de l'emploi du temps à mettre à jour
     * @param newStatut statut de l'emploi du temps
     * @return 0 si la mis à jour s'est bien déroulée, -1 sinon
     */
    public int updateStatutLesson(long id, String scheduleName, int newStatut) {
        this.open();
        ContentValues values = new ContentValues();
        values.put(COL_CHANGE, newStatut);
        int resUpt = this.bdd.update(TABLE_LESSON, values,
                String.format("%s = '%s' AND %s = '%s'", COL_LESSON_ID, id, COL_SCHEDULE, scheduleName),
                null);
        this.close();
        return resUpt;
    }//updateStatutLesson(long id,String scheduleName,int newStatut)   

    /**
     * Supprime un cours dans la table LESSON, identifié par l'id du cours.
     *
     * @param id id du cours à supprimer
     * @return 0 si aucune suppression, le nombre de tuples supprimés sinon
     * @deprecated La supression se fait via le nom de l'emploi du temps : {@link #removeScheduleLessonsWithName(java.lang.String) removeScheduleLessonsWithName()}
     */
    public int removeLessonWithID(int id) {
        this.open();
        //Suppression d'un cours de la BDD
        int resDel = this.bdd.delete(TABLE_LESSON, COL_LESSON_ID + " = " + id, null);
        this.close();
        return resDel;
    }//removeLessonWithID(int id

    /**
     * Retourne
     * <code>Lesson</code> extrait de la table Lesson grâce à l'id du cours et
     * le nom de l'emploi du temps.
     *
     * @param id id du cours
     * @param scheduleName nom de l'emploi du temps
     * @return
     * <code>Lesson</code>
     */
    public Lesson getLessonWithID(long id, String scheduleName) {
        this.open();
        //Récupère dans un Cursor les valeurs correspondantent à un cours contenu dans la BDD
        Cursor c = bdd.query(TABLE_LESSON,
                new String[]{COL_LESSON_ID, COL_TITLE, COL_TIME, COL_SCHEDULE, COL_TYPE, COL_CHANGE,
                    COL_LASTMODIF, COL_ROOM, COL_GROUP, COL_TEACHER, COL_COLOR, COL_NOTE},
                String.format("%s = '%s' AND %s = '%s'", COL_LESSON_ID, id, COL_SCHEDULE, scheduleName),
                null, null, null, null, null);
        Lesson lesson = this.cursorToLesson(c);
        c.close();
        return lesson;
    }//getLessonWithID(long id, String scheduleName)

    /**
     * Conversion d'un type
     * <code>Cursor</code> en
     * <code>Lesson</code>. Toute fonction jdbc retourne un type
     * <code>Cursor</code>, cette méthode est appelé après chaque requête afin
     * retourner directement un
     * <code>Lesson</code>.
     *
     * @param c Cursor
     * @return
     * <code>Lesson</code>, null si le curseur est vide.
     */
    public static Lesson cursorToLesson(Cursor c) {
        Lesson l = null;
        if (c.moveToNext()) {
            l = new Lesson();
            //on lui affecte toutes les infos grâce aux infos contenues dans le Cursor             
            l.setLessonId(c.getInt(NUM_COL_LESSON_ID));
            l.setTitle(c.getString(NUM_COL_TITLE));
            l.setTime(c.getString(NUM_COL_TIME));
            l.setSchedule(c.getString(NUM_COL_SCHEDULE));
            l.setType(c.getInt(NUM_COL_TYPE));
            l.setChange(c.getInt(NUM_COL_CHANGE));
            l.setRoom(c.getString(NUM_COL_ROOM));
            l.setGroups(c.getString(NUM_COL_GROUP));
            l.setTeachers(c.getString(NUM_COL_TEACHER));
            l.setCreated(c.getString(NUM_COL_LASTMODIF));
            l.setColor(c.getString(NUM_COL_COLOR));
            l.setNote(c.getString(NUM_COL_NOTE));
        }// if

        //On retourne le cours
        return l;
    }

    /**
     * Retourne un tableau de
     * <code>Lesson</code> associé à un emploi du temps, identifié par son nom.
     * Retourne tous les cours d'un emploi du temps.
     *
     * @param schedule nom de l'emploi du temps
     * @return tableau de
     * <code>Lesson</code> associé à un emploi du temps
     */
    public Lesson[] getLessonByScheduleName(String schedule) {
        this.open();
        Cursor c = this.bdd.query(TABLE_LESSON,
                new String[]{COL_LESSON_ID, COL_TITLE, COL_TIME, COL_SCHEDULE, COL_TYPE, COL_CHANGE,
                    COL_ROOM, COL_GROUP, COL_TEACHER,COL_LASTMODIF ,COL_COLOR,COL_NOTE},
                  COL_SCHEDULE + " LIKE \"" + schedule + "\"",
                null, 
                null, 
                null, 
                "TIME ASC", // ORDER BY
                null);

        ArrayList<Lesson> liste = new ArrayList<Lesson>();
        Lesson l = Database.cursorToLesson(c);
        while (l != null) {
            liste.add(l);
            l = Database.cursorToLesson(c);
        }// while
        c.close();
        this.close();
        //this.bdd.close();
        return liste.toArray(new Lesson[liste.size()]);
    }

    /**
     * Retourne un
     * <code>Cursor</code>, cours d'un emploi du temps, identidié par
     * <code>Schedule</code> ayant des dates supérieurs à la date courante (date
     * + heure).
     *
     * @param s
     * <code>Schedule</code>
     * @return
     * <code>Cursor</code>
     */
    public Cursor getLessonsCursor(Schedule s) {
        this.open();
        Cursor c = bdd.query(TABLE_LESSON,
                new String[]{COL_LESSON_ID, COL_TITLE, COL_TIME, COL_SCHEDULE, COL_TYPE, COL_CHANGE, COL_LASTMODIF, COL_ROOM, COL_GROUP, COL_TEACHER, COL_COLOR, COL_NOTE},
                String.format("%s = '%s' AND TIME >= strftime('%%Y/%%m/%%d %%H:%%M', 'now')", COL_SCHEDULE, s.getName()),
                null, // SELECTION ARRAYS (binding ? to variables)
                null, // GROUP BY
                null, // HAVING
                "TIME ASC", // ORDER BY
                null);// LIMIT
        //this.close() ;
        return c;

    }// getLessonsCursor(Schedule)
    
    /**
     * Retourne un
     * <code>Cursor</code>, cours d'un emploi du temps, identidié par
     * <code>Schedule</code>.
     *
     * @param s
     * <code>Schedule</code>
     * @return
     * <code>Cursor</code>
     */
    public Cursor getAllLessonsCursor(Schedule s) {
        this.open();
        Cursor c = bdd.query(TABLE_LESSON,
                new String[]{COL_LESSON_ID, COL_TITLE, COL_TIME, COL_SCHEDULE, COL_TYPE, COL_CHANGE, COL_LASTMODIF, COL_ROOM, COL_GROUP, COL_TEACHER, COL_COLOR, COL_NOTE},
                String.format("%s = '%s'", COL_SCHEDULE, s.getName()),
                null, // SELECTION ARRAYS (binding ? to variables)
                null, // GROUP BY
                null, // HAVING
                "TIME ASC", // ORDER BY
                null);// LIMIT
        //this.close() ;
        return c;

    }// getLessonsCursor(Schedule)

    /**
     * Insère tous les cours de la liste dans la table LESSON. Appel à {@link #removeScheduleLessonsWithName(String name) removeScheduleLessonsWithName(String name)}
     * sur tous les
     * <code>LESSON</code>
     *
     * @param lessons
     * <code>ArrayList<Lesson></code> liste de cours.
     * @throws AAAException
     */
    public void insertLessons(ArrayList<Lesson> lessons) throws AAAException {
        try {
            this.open();
            this.bdd.beginTransaction();
            for (Lesson l : lessons) {
                this.insertLesson(l);
            }// for
            this.bdd.setTransactionSuccessful();
        } catch (IllegalStateException e) {
            throw new AAAInternalException("Erreur lors de l'insertion de cours.");
        } finally {
            this.bdd.endTransaction();
            this.close();
        }// try
    }// insertLessons(ArrayList<Lesson>)

    /**
     * Met à jour tous les cours de la liste dans la table LESSON. Appel à {@link #updateLessons(java.util.ArrayList)  updateLessons()}
     * sur tous les
     * <code>LESSON</code>
     *
     * @param lessons
     * <code>ArrayList<Lesson></code> liste de cours.
     * @throws AAAException
     */
    public void updateLessons(ArrayList<Lesson> lessons) throws AAAException {
        for (Lesson l : lessons) {
            this.updateLesson(l.getLessonId(), l.getSchedule(), l);
        }// for
    }// updateLessons(ArrayList<Lesson>)

    /**
     * Supprime tous les cours de la liste dans la table LESSON associé au nom
     * d'unemploi du temps.
     *
     * @param lessons
     * <code>ArrayList<Lesson></code> liste de cours.
     * @param scheduleName nom de l'emploi du temps.
     * @return 0 si aucune suppression, le nombre de tuples sinon
     */
    public int deleteLessons(ArrayList<Lesson> lessons, String scheduleName) {
        this.open();
        // Build the where condition
        StringBuilder ids = new StringBuilder();
        for (Lesson l : lessons) {
            ids.append(",");
            ids.append(l.getLessonId());
        }// for
        String where = String.format("%s IN (%s) AND %s = '%s'",
                Database.COL_LESSON_ID, ids.substring(1),
                COL_SCHEDULE, scheduleName);
        //Suppression d'un cours de la BDD
        int resDel = this.bdd.delete(TABLE_LESSON, where, null);
        this.close();
        return resDel;
    }// deleteLessons(ArrayList<Lesson>)

    //------------------------------------------------------------------------------------------------
    //--------------------------------------- Numéro étudiant ------------------------------------------
    /**
     * Insère un numéro étudiant et ses ressources associées dans la table
     * STUDENTNUMBER.
     *
     * @param sn
     * <code>StundentNumber</code>
     * @return -1 si échec, la ligne du tuple inséré sinon
     */
    public long insertStudentNumber(StudentNumber sn) {
        //Création d'un ContentValues (fonctionne comme une HashMap)
        ContentValues values = new ContentValues();
        //on lui ajoute une valeur associée à une clé (qui est le nom de la colonne dans laquelle on veut mettre la valeur)
        values.put(COL_STUDENT_NUMBER, sn.getStudentNumber());
        values.put(COL_RESSOURCEID, sn.getRessources());
        Log.i("studentNum", "insertionStudentNum");
        long resInsert = bdd.insertOrThrow(TABLE_STUDENT_NUMBER, null, values);
        Log.i("studentNum", resInsert + "");
        return resInsert;
    }

    /**
     * Met à jour un numéro étudiant et ses ressources associées dans la table
     * STUDENTNUMBER, identifié par le numéro étudiant.
     *
     * @param number numéro étudiant
     * @param sn
     * <code>StundentNumber</code>
     * @return -1 si échec, la ligne du tuple modifié sinon
     */
    public int updateStudentNumber(String number, StudentNumber sn) {

        ContentValues values = new ContentValues();
        values.put(COL_STUDENT_NUMBER, sn.getStudentNumber());
        values.put(COL_RESSOURCEID, sn.getRessources());
        int resUpdate = bdd.update(TABLE_STUDENT_NUMBER, values, String.format("%s = \"%s\"", COL_STUDENT_NUMBER, number), null);
        // UPDATE STUDENTNUMBER SET SCHEDULE = s.getName() WHERE SCHEDULE = name only if name != s.getName() 
        return resUpdate;
    }

    /**
     * Supprime un numéro étudiant et ses ressources associées dans la table
     * STUDENTNUMBER, identifié par le numéro étudiant.
     *
     * @param number numéro étudiant
     * @return 0 si aucune suppression, le nombre de tuples supprimés sinon
     */
    public int removeStudentNumber(String number) {
        this.open();
        //Suppression d'un numero étudiant de la BDD
        int resDel = this.bdd.delete(TABLE_STUDENT_NUMBER, COL_STUDENT_NUMBER + " = " + number, null);
        this.close();
        return resDel;
    }

    /**
     * Retourne
     * <code>StundentNumber</code> extrait de la table STUDENTNUMBER grâce au
     * numéro étudiant.
     *
     * @param number numéro étudiant
     * @return
     * <code>StundentNumber</code>
     */
    public StudentNumber getRessourceWithStudentNumber(String number) {
        //Récupère dans un Cursor les valeurs correspondantent à un cours contenu dans la BDD
        Cursor c = bdd.query(TABLE_STUDENT_NUMBER,
                new String[]{COL_STUDENT_NUMBER, COL_RESSOURCEID},
                String.format("%s = '%s'", COL_STUDENT_NUMBER, number),
                null, null, null, null, null);
        StudentNumber sn = this.cursorToStudentNumber(c);
        c.close();
        return sn;
    }

    /**
     * Conversion d'un type
     * <code>Cursor</code> en
     * <code>StundentNumber</code>. Toute fonction jdbc retourne un type
     * <code>Cursor</code>, cette méthode est appelé après chaque requête afin
     * retourner directement un
     * <code>StundentNumber</code>.
     *
     * @param c Cursor
     * @return
     * <code>StundentNumber</code>, null si le curseur est vide.
     */
    private StudentNumber cursorToStudentNumber(Cursor c) {
        StudentNumber sn = null;
        if (c.moveToNext()) {
            sn = new StudentNumber();
            //on lui affecte toutes les infos grâce aux infos contenues dans le Cursor          
            sn.setStudentNumber(c.getString(NUM_COL_STUDENT_NUMBER));
            sn.setRessources(c.getString(NUM_COL_RESSOURCEID));
        }

        return sn;
    }

    //------------------------------------------------------------------------------------------------
    //--------------------------------------- Historique Cours ------------------------------------------
    /**
     * Insère l'historique d'un cours dans la table LESSON_HISTORY.
     *
     * @param l
     * <code>Lesson</code> un cours.
     * @return -1 si échec, la ligne du tuple inséré sinon
     */
    public long insertLessonHistory(Lesson l) {
        this.open();
        long res = 0;
        if (this.getLessonHistoryWithID(l.getLessonId(), l.getSchedule()) == null) {
        // Get the InsertHelper ready to insert a single row
        this.lessonHistoryInsert.prepareForInsert();
        
        // Add the data for each column
        this.lessonHistoryInsert.bind(1 + Database.NUM_COL_LESSON_ID, l.getLessonId());
        this.lessonHistoryInsert.bind(1 + Database.NUM_COL_TITLE, l.getTitle());
        this.lessonHistoryInsert.bind(1 + Database.NUM_COL_TIME, l.getTime());
        this.lessonHistoryInsert.bind(1 + Database.NUM_COL_SCHEDULE, l.getSchedule());
        this.lessonHistoryInsert.bind(1 + Database.NUM_COL_TYPE, l.getType());
        this.lessonHistoryInsert.bind(1 + Database.NUM_COL_CHANGE, l.getChange());
        this.lessonHistoryInsert.bind(1 + Database.NUM_COL_ROOM, l.getRoom());
        this.lessonHistoryInsert.bind(1 + Database.NUM_COL_GROUP, l.getGroups());
        this.lessonHistoryInsert.bind(1 + Database.NUM_COL_TEACHER, l.getTeacher());
        this.lessonHistoryInsert.bind(1 + Database.NUM_COL_LASTMODIF, l.getCreated());
        this.lessonHistoryInsert.bind(1 + Database.NUM_COL_COLOR, l.getColor());    
        this.lessonHistoryInsert.bind(1 + Database.NUM_COL_NOTE, l.getNote());   
            // Insert the row into the database.
            res =  this.lessonHistoryInsert.execute();
        } else {
            
           res = this.updateLessonHistory(l.getLessonId(), l.getSchedule(), l); 
        }
        return res;
    }// insertLessonHistory(Lesson)

    /**
     * Retourne
     * <code>Lesson</code> extrait de la table LESSON_HISTORY grâce à l'id du
     * cours et le nom de l'emploi du temps.
     *
     * @param id id du cours
     * @param scheduleName nom de l'emploi du temps
     * @return
     * <code>Lesson</code>
     */
    public Lesson getLessonHistoryWithID(long id, String scheduleName) {
        this.open();
        //Récupère dans un Cursor les valeurs correspondantent à un cours contenu dans la BDD
        Cursor c = bdd.query(TABLE_LESSON_HISTORY,
                new String[]{COL_LESSON_ID, COL_TITLE, COL_TIME, COL_SCHEDULE, COL_TYPE, COL_CHANGE,
                    COL_LASTMODIF, COL_ROOM, COL_GROUP, COL_TEACHER, COL_COLOR, COL_NOTE},
                String.format("%s = '%s' AND %s = '%s'", COL_LESSON_ID, id, COL_SCHEDULE, scheduleName),
                null, null, null, null, null);
        Lesson lesson = this.cursorToLesson(c);
        c.close();
        return lesson;
    }//getLessonHistoryWithID(long id, String scheduleName)

    /**
     * Supprime un cours dans la table LESSON_HISTORY, identifié par l'id de
     * l'historique du cours.
     *
     * @param id id du cours à supprimer
     * @param schedule emploi du temps dans lequel est le cours à supprimer
     * @return 0 si aucune suppression, le nombre de tuples supprimés sinon
     */
    public int removeLesson_HistoryWithID(long id, String schedule) {
        this.open();
        //Suppression d'un cours de la BDD
        int resDel = this.bdd.delete(TABLE_LESSON_HISTORY, String.format("%s = '%s' AND %s = '%s'", COL_LESSON_ID, id, COL_SCHEDULE, schedule), null);
        this.close();
        return resDel;
    }//removeLesson_HistoryWithID(int id
    
    /**
     * Met à jour l'historique d'un cours dans la table LESSON_HISTORY, identifié par l'id du cours et
     * le nom de l'emploi du temps associé.
     *
     * @param oldId id du cours
     * @param oldSchedule nom de l'emploi du temps
     * @param newLesson
     * <code>Lesson</code> avec en champ les nouveaux paramètres
     * @return -1 si échec, la ligne du tuple modifié sinon
     */
    public int updateLessonHistory(long oldId, String oldSchedule, Lesson newLesson) {
        this.open();
        //La mise à jour de l'historique d'un cours dans la BDD fonctionne plus ou moins comme une insertion
        //il faut simple préciser quel cours on doit mettre à jour grâce à son ID
        ContentValues values = new ContentValues();
        values.put(COL_LESSON_ID, newLesson.getLessonId());
        values.put(COL_TITLE, newLesson.getTitle());
        values.put(COL_TIME, newLesson.getTime());
        values.put(COL_SCHEDULE, newLesson.getSchedule());
        values.put(COL_TYPE, newLesson.getType());
        values.put(COL_CHANGE, newLesson.getChange());
        values.put(COL_ROOM, newLesson.getRoom());
        values.put(COL_GROUP, newLesson.getGroups());
        values.put(COL_TEACHER, newLesson.getTeacher());
        values.put(COL_LASTMODIF, newLesson.getCreated());
        values.put(COL_COLOR, newLesson.getColor());
        values.put(COL_NOTE, newLesson.getNote());
        int resUpt = this.bdd.update(TABLE_LESSON_HISTORY, values,
                String.format("%s = '%s' AND %s = '%s'", COL_LESSON_ID, oldId, COL_SCHEDULE, oldSchedule),
                null);
        this.close();
        return resUpt;
    }
    //------------------------------------------------------------------------------------------------
}
